using LogSystem;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using System.Linq;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.City
{
    [Serializable]
    public class CitySubArea
    {
        public int areaId;
        public int minX;
        public int maxX;
        public int minY;
        public int maxY;
        public List<RectInt> grids;
    }

    [Serializable]
    public class CityAreaConfig
    {
        public int width;
        public int height;
        
        public List<CitySubArea> citySubAreas;
        private Dictionary<int, CitySubArea> _subAreaMap;
        public void InitMap()
        {
            _subAreaMap = new Dictionary<int, CitySubArea>();
            foreach (var subArea in citySubAreas)
            {
                _subAreaMap[subArea.areaId] = subArea;
            }
        }

        public CitySubArea GetArea(int areaId)
        {
            _subAreaMap.TryGetValue(areaId, out CitySubArea area);
            return area;
        }
    }

    [Serializable]
    public class CitySubAreaEditor
    {
        public int areaId;
        public List<Vector2Int> grids;
    }
    
    [Serializable]
    public class CitySubAreaEditorRec
    {
        public int areaId;
        public List<RectInt> grids;
    }
    
    [Serializable]
    public class CitySubAreaEditorExtend
    {
        public int areaId;
        public int minX;
        public int maxX;
        public int minY;
        public int maxY;
        public List<RectInt> grids;
    }

    [Serializable]
    public class CityAreaEditorConfig
    {
        public int width;
        public int height;
        
        public List<CitySubAreaEditor> citySubAreas;
    }
    
    [Serializable]
    public class CityAreaEditorConfigRec
    {
        public int width;
        public int height;
        
        public List<CitySubAreaEditorRec> citySubAreas;
    }
    
    [Serializable]
    public class CityAreaEditorConfigExtend
    {
        public int width;
        public int height;
        
        public List<CitySubAreaEditorExtend> citySubAreas;
    }

    [Serializable]
    public class AreaEditorConfig
    {
        public int areaId;
        public Color color = Color.red;
    }
    
    public class AreaEditorBase : CityEditorBase
    {
        [Header("服务器配置存放路径")]
        public string serverConfigPath;
        [Header("用于缓存编辑的区域")]
        public string editorConfigPath;

        [Header("用于编辑时显示区域，Quad")]
        public MeshRenderer areaRenderer;
        private string areaMaskTexturePath = "Assets/ResourcesAssets/City/Texture/tex_cityAreaMask_{0}.png";
        protected int[,] areaIdArray;
        protected Texture2D areaTexture;
        protected Dictionary<int, Texture2D> areaMaskTextures = new Dictionary<int, Texture2D>();
        private Color maskColor = Color.red;
        private Color baseColor = Color.clear;

        public List<AreaEditorConfig> areaConfigs;
        
        protected Dictionary<int, AreaEditorConfig> _areaConfigMap;
        
        [DisplayOnly]
        public bool editing;

        public int currentAreaId;

        [Range(0,1)]
        public float alpha = 0.3f;
        

        private void Init()
        {
            _areaConfigMap = new Dictionary<int, AreaEditorConfig>();
            if (areaConfigs != null)
            {
                foreach (var areaConfig in areaConfigs)
                {
                    _areaConfigMap[areaConfig.areaId] = areaConfig;
                }
            }
            
            areaRenderer.transform.rotation = Quaternion.Euler(90,gridViewAngleY,0);
            areaRenderer.transform.localScale = new Vector3(width * cityCellSize.x, height * cityCellSize.z,1 );
            
            areaRenderer.sharedMaterial.SetInt("_GridWidth",width);
            areaRenderer.sharedMaterial.SetInt("_GridHeight",height);

            gridRenderer.transform.localScale = new Vector3(width * cityCellSize.x * 0.1f,  1, height * cityCellSize.z * 0.1f);
            gridRenderer.sharedMaterial.SetTextureScale("_GridTex",new Vector2(width,height));

            StartCoroutine(GenerateGridCoordinateText());
        }
        
        private void Update()
        {
            UpdateEdit();
        }

        private void UpdateEdit()
        {
            if (!editing) return;
            if (!cityCamera)
            {
                Debug.LogError(LogModule.City,"没有指定摄像机！！！");
                return;
            }
            OnEditing();
        }
        
        protected Vector2Int lastGrid = new Vector2Int(-1,-1);

        protected virtual void OnEditing()
        {
            if (Input.GetKey(KeyCode.LeftControl))
            {
                // 按住Ctrl，画矩形
                RectangleModeEdit();
            }
            else
            {
                ResetRectangleMode();
                GridModeEditing();
            }
        }

        /// <summary>
        /// 单格的设置和取消编辑模式
        /// </summary>
        private void GridModeEditing()
        {
            if (Input.GetMouseButton(1))
            {
                Vector3 hitPos;
                if (GetClickPos(Input.mousePosition, out hitPos))
                {
                    Vector2Int grid = GetGrid(hitPos);
                    if (lastGrid.x == grid.x && lastGrid.y == grid.y)
                    {
                        return;
                    }

                    if (grid.x < 0 || grid.x >= width || grid.y < 0 || grid.y >= height)
                    {
                        return;
                    }

                    lastGrid = grid;
                    WritePixel(grid);
                    areaTexture.Apply();
                }
            }

            if (Input.GetMouseButton(2))
            {
                Vector3 hitPos;
                if (GetClickPos(Input.mousePosition, out hitPos))
                {
                    Vector2Int grid = GetGrid(hitPos);
                    if (lastGrid.x == grid.x && lastGrid.y == grid.y)
                    {
                        return;
                    }

                    if (grid.x < 0 || grid.x >= width || grid.y < 0 || grid.y >= height)
                    {
                        return;
                    }

                    lastGrid = grid;
                    ClearPixel(grid);
                    areaTexture.Apply();
                }
            }
        }

        protected void WritePixel(Vector2Int grid)
        {
            if (_areaConfigMap.ContainsKey(currentAreaId))
            {
                areaTexture.SetPixel(grid.x, grid.y, _areaConfigMap[currentAreaId].color);
                // 写入数据中
                areaIdArray[grid.x, grid.y] = currentAreaId;
            }
        }

        protected void ClearPixel(Vector2Int grid)
        {
            areaTexture.SetPixel(grid.x, grid.y, Color.clear);
            areaIdArray[grid.x, grid.y] = 0;
        }

        public void Begin()
        {
            if (cityCamera == null)
            {
                if (Camera.main && Camera.main.enabled)
                {
                    cityCamera = Camera.main;
                }
            }
            
            if (cityCamera == null || cityRoot == null || areaRenderer == null)
            {
                Debug.LogError(LogModule.City,"相机、根节点或者AreaRenderer为空~");
                return;
            }
            collider.transform.gameObject.SetActive(true);
            editing = true;
            Show();
        }

        public void End()
        {
            UnShow();
            Save();
            editing = false;
            collider.transform.gameObject.SetActive(false);
        }
        
        public void Show()
        {
#if UNITY_EDITOR

            Init();

            areaRenderer.enabled = true;
            gridRenderer.enabled = true;
            
            if (File.Exists(editorConfigPath))
            {
                var areaText = AssetDatabase.LoadAssetAtPath<TextAsset>(editorConfigPath).text;
                CityAreaEditorConfig areaConfig = JsonUtility.FromJson<CityAreaEditorConfig>(areaText);
                width = areaConfig.width;
                height = areaConfig.height;
                areaIdArray = new int[width, height];
                // 长宽一样
                if (areaConfig.width == width && areaConfig.height == height)
                {
                    if (areaConfig.citySubAreas != null)
                    {
                        foreach (var citySubArea in areaConfig.citySubAreas)
                        {
                            if (citySubArea.grids != null)
                            {
                                foreach (var grid in citySubArea.grids)
                                {
                                    if (_areaConfigMap.ContainsKey(citySubArea.areaId))
                                    {
                                        areaIdArray[grid.x, grid.y] = citySubArea.areaId;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                areaIdArray = new int[width, height];
            }

            // 根据迷雾数字写入像素
            areaTexture = new Texture2D(width, height, TextureFormat.RGBAFloat, false, false);
            areaTexture.filterMode = 0;
            for (int i = 0; i < areaIdArray.GetLength(0); i++)
            {
                for (int j = 0; j < areaIdArray.GetLength(1); j++)
                {
                    int areaId = areaIdArray[i, j];
                    if (areaId!=0 && _areaConfigMap.ContainsKey(areaId))
                    {
                        areaTexture.SetPixel(i, j, _areaConfigMap[areaId].color);
                    }
                    else
                    {
                        areaTexture.SetPixel(i, j, baseColor);
                    }
                }
            }
            areaTexture.Apply();
            areaRenderer.sharedMaterial.SetTexture("_UVTex",areaTexture);
#endif
        }
        
        public virtual void UnShow()
        {
            areaRenderer.enabled = false;
            gridRenderer.enabled = false;
            areaRenderer.transform.localScale = Vector3.zero;
        }

        public virtual void Save()
        {
#if UNITY_EDITOR

            if (!editing) return;

            areaMaskTextures.Clear();
            // 保存编辑器配置
            CityAreaEditorConfig areaConfig = new CityAreaEditorConfig();
            areaConfig.width = width;
            areaConfig.height = height;
            areaConfig.citySubAreas = new List<CitySubAreaEditor>();

            Dictionary<int, CitySubAreaEditor> citySubAreaMap = new Dictionary<int, CitySubAreaEditor>();

            for (int i = 0; i < areaIdArray.GetLength(0); i++)
            {
                for (int j = 0; j < areaIdArray.GetLength(1); j++)
                {
                    int areaId = areaIdArray[i, j];
                    if (areaId <= 0)
                    {
                        continue;
                    }
                    
                    if (!citySubAreaMap.ContainsKey(areaId))
                    {
                        CitySubAreaEditor subFog = new CitySubAreaEditor();
                        subFog.areaId = areaId;
                        subFog.grids = new List<Vector2Int>();
                        citySubAreaMap[areaId] = subFog;
                    }
                    
                    citySubAreaMap[areaId].grids.Add(new Vector2Int(i,j));

                    if (!areaMaskTextures.ContainsKey(areaId))
                    {
                        areaMaskTextures[areaId] = new Texture2D(width, height, TextureFormat.RGBA32, false, true);
                    }
                }
            }
            
            areaConfig.citySubAreas.AddRange(citySubAreaMap.Values);

            var jsonText = JsonUtility.ToJson(areaConfig,false);
            FileStream fs = new FileStream(editorConfigPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(fs))
            {
                writer.Write(jsonText);
                writer.Flush();
                writer.Close();
                fs.Close();
            }
            AssetDatabase.Refresh();
            
            // 保存服务器配置
            CityAreaConfig serverConfig = new CityAreaConfig();
            serverConfig.width = areaConfig.width;
            serverConfig.height = areaConfig.height;

            serverConfig.citySubAreas = new List<CitySubArea>();
            
            if (areaConfig.citySubAreas!=null)
            {
                for (int i = 0; i < areaConfig.citySubAreas.Count; i++)
                {
                    var editorArea = areaConfig.citySubAreas[i];
                    CitySubArea subArea = new CitySubArea();
                    subArea.areaId = editorArea.areaId;

                    int minX = 9999;
                    int maxX = -9999;
                    int minY = 9999;
                    int maxY = -9999;
                    foreach (var grid in editorArea.grids)
                    {
                        if (grid.x < minX) minX = grid.x;
                        if (grid.x > maxX) maxX = grid.x;
                        
                        if (grid.y < minY) minY = grid.y;
                        if (grid.y > maxY) maxY = grid.y;
                    }

                    subArea.minX = minX;
                    subArea.maxX = maxX;
                    subArea.minY = minY;
                    subArea.maxY = maxY;
                    
                    
                    serverConfig.citySubAreas.Add(subArea);
                }
            }

//            SaveBaseArea(serverConfig);
            // 存储为矩形结构
            SaveRecArea(citySubAreaMap);
            GenerateMaskTexture();
#endif
        }

        //mask贴图生成
        void GenerateMaskTexture()
        {
#if UNITY_EDITOR
            foreach (var config in areaMaskTextures)
            {
                for (int i = 0; i < areaIdArray.GetLength(0); i++)
                {
                    for (int j = 0; j < areaIdArray.GetLength(1); j++)
                    {
                        int areaId = areaIdArray[i, j];
                        if (areaId > 1 && _areaConfigMap.ContainsKey(areaId) && areaId <= config.Key)
                        {
                           areaMaskTextures[config.Key].SetPixel(i, j, maskColor); 
                        }
                        else
                        {
                            areaMaskTextures[config.Key].SetPixel(i, j, baseColor); 
                        }
                    }
                }
                areaMaskTextures[config.Key].Apply();
            }
            
            foreach (var config in areaMaskTextures)
            {
                string areaMaskPath = string.Format(areaMaskTexturePath, config.Key);
                byte[] dataBytes = config.Value.EncodeToPNG();
                File.WriteAllBytes(PathUtility.AssetPathToFullPath(areaMaskPath), dataBytes);
                AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
                TextureImporter textureImporter = AssetImporter.GetAtPath(areaMaskPath) as TextureImporter;
                if (textureImporter != null)
                {
                    textureImporter.sRGBTexture = false;
                    textureImporter.npotScale = TextureImporterNPOTScale.None;
                    textureImporter.mipmapEnabled = false;
                    textureImporter.isReadable = true;
                    AssetDatabase.ImportAsset(areaMaskPath);
                    AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
                }
            }
#endif
        }

        public void SaveBaseArea(CityAreaConfig serverConfig)
        {
#if UNITY_EDITOR
            var jsonText2 = JsonUtility.ToJson(serverConfig,false);
            FileStream fs2 = new FileStream(serverConfigPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(fs2))
            {
                writer.Write(jsonText2);
                writer.Flush();
                writer.Close();
                fs2.Close();
            }
            AssetDatabase.Refresh();
#endif
        }
        
        public void SaveRecArea(Dictionary<int, CitySubAreaEditor> citySubAreaMap)
        {
#if UNITY_EDITOR
            if (!editing) return;
            var areaConfigRec = new CityAreaEditorConfigExtend
            {
                width = width,
                height = height,
                citySubAreas = new List<CitySubAreaEditorExtend>()
            };
            var citySubAreaMapRec = new Dictionary<int, CitySubAreaEditorExtend>();
            foreach (var citySubAreaMapIndex in citySubAreaMap.Keys)
            {
                var grids = citySubAreaMap[citySubAreaMapIndex].grids;
                if (!citySubAreaMapRec.ContainsKey(citySubAreaMapIndex))
                {
                    // 初始化key
                    CitySubAreaEditorExtend citySubAreaEditorRecValue = new CitySubAreaEditorExtend();
                    citySubAreaEditorRecValue.areaId = citySubAreaMapIndex;
                    citySubAreaEditorRecValue.grids = new List<RectInt>();
                    citySubAreaMapRec[citySubAreaMapIndex] = citySubAreaEditorRecValue;
                }
                var grs = MergeOneArea(grids);
                int minX = 9999;
                int maxX = -9999;
                int minY = 9999;
                int maxY = -9999;
                foreach (var grid in grs)
                {
                    if (grid.xMin < minX) minX = grid.xMin;
                    if (grid.xMax > maxX) maxX = grid.xMax;
                        
                    if (grid.yMin < minY) minY = grid.yMin;
                    if (grid.yMax > maxY) maxY = grid.yMax;
                }
                citySubAreaMapRec[citySubAreaMapIndex].minX = minX;
                citySubAreaMapRec[citySubAreaMapIndex].maxX = maxX;
                citySubAreaMapRec[citySubAreaMapIndex].minY = minY;
                citySubAreaMapRec[citySubAreaMapIndex].maxY = maxY;
                citySubAreaMapRec[citySubAreaMapIndex].grids = grs;
            }

            // 以矩形方式保存
            areaConfigRec.citySubAreas.AddRange(citySubAreaMapRec.Values);
            // 以矩形方式保存配置
            var jsonTextRec = JsonUtility.ToJson(areaConfigRec, false);
            FileStream fs3 = new FileStream(serverConfigPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(fs3))
            {
                writer.Write(jsonTextRec);
                writer.Flush();
                writer.Close();
                fs3.Close();
            }
            AssetDatabase.Refresh();
#endif
        }
        
        // 合并单个区域的所有点坐标为矩形坐标
        public List<RectInt> MergeOneArea(List<Vector2Int> grids)
        {
            int curX = 0;
            int curYStart = 0;
            int curYEnd = 0;
            // 合并 x 
            Dictionary<int, List<int[]>> xDic = new Dictionary<int, List<int[]>>();
            foreach (var grid in grids)
            {
                if (xDic.ContainsKey(grid.x))
                {
                    if (grid.y - xDic[grid.x].Last()[1] == 1)
                    {
                        xDic[grid.x].Last()[1] = grid.y;
                    }
                    else
                    {
                        int[] tmp = {grid.y, grid.y};
                        xDic[grid.x].Add(tmp);
                    }
                }
                else
                {
                    int[] tmp = {grid.y, grid.y};
                    List<int[]> tmpList = new List<int[]>();
                    tmpList.Add(tmp);
                    xDic.Add(grid.x, tmpList);
                }
            }
            // PrintDic(xDic);
            // 合并同一个 x 方向上的 y 坐标
            Dictionary<string, List<int[]>> yDic = new Dictionary<string, List<int[]>>();
            foreach (var xDicX in xDic.Keys)
            {
                foreach (var xDicXArray in xDic[xDicX])
                {
                    string heightRange = $"{xDicXArray[0]},{xDicXArray[1]}";
                    if (yDic.ContainsKey(heightRange))
                    {
                        if (xDicX - yDic[heightRange].Last()[1] == 1)
                        {
                            yDic[heightRange].Last()[1] = xDicX;
                        }
                        else
                        {
                            int[] tmp = {xDicX, xDicX};
                            yDic[heightRange].Add(tmp);
                        }
                    }
                    else
                    {
                        int[] xRange = {xDicX, xDicX};
                        List<int[]> tmpList = new List<int[]>();
                        tmpList.Add(xRange);
                        yDic.Add(heightRange, tmpList);
                    }
                }
            }
            List<RectInt> Recs = new List<RectInt>();
            foreach (string yRange in yDic.Keys)
            {
                List<string> yRangeList = new List<string>(yRange.Split(','));
                int y1 = int.Parse(yRangeList[0]);
                int y2 = int.Parse(yRangeList[1]);
                foreach (var xList in yDic[yRange])
                {
                    
                    int x1 = xList[0];
                    int x2 = xList[1];
                    RectInt rec = new RectInt(x1, y1, x2 - x1, y2 - y1);
                    Recs.Add(rec);
                }
            }
            return Recs;
        }


#if UNITY_EDITOR

        public void OnValidate()
        {
            if (areaRenderer)
            {
                areaRenderer.sharedMaterial.SetFloat("_AlphaValue",alpha);
            }
        }
#endif


        #region 刷矩形格子
        private bool isFirstGridSet = false;
        private Vector2Int fisrtGrid;
        private bool isSecondGridSet = false;
        private Vector2Int secondGrid;

        protected int[,] backupAreaIdArray;

        /// <summary>
        /// 按住Ctrl键之后，将两个点当成对角线填充矩形，方便快速刷大面积的区域
        /// </summary>
        protected void RectangleModeEdit()
        {
            if (Input.GetMouseButton(1))
            {
                Vector3 hitPos;
                if (GetClickPos(Input.mousePosition, out hitPos))
                {
                    Vector2Int grid = GetGrid(hitPos);

                    if (grid.x < 0 || grid.x >= width || grid.y < 0 || grid.y >= height)
                    {
                        return;
                    }

                    if (isFirstGridSet)
                    {
                        if (isSecondGridSet)
                        {
                            RecoverRectangle();
                        }

                        secondGrid = grid;
                        isSecondGridSet = true;
                        FillRectangle();
                        areaTexture.Apply();
                    }
                    else
                    {
                        BackupArea();
                        isFirstGridSet = true;
                        fisrtGrid = grid;
                        WritePixel(fisrtGrid);
                        areaTexture.Apply();
                    }
                }
            }
            else  if (Input.GetMouseButton(2))
            {
                Vector3 hitPos;
                if (GetClickPos(Input.mousePosition, out hitPos))
                {
                    Vector2Int grid = GetGrid(hitPos);

                    if (grid.x < 0 || grid.x >= width || grid.y < 0 || grid.y >= height)
                    {
                        return;
                    }

                    if (isFirstGridSet)
                    {
                        if (isSecondGridSet)
                        {
                            RecoverRectangle();
                        }

                        secondGrid = grid;
                        isSecondGridSet = true;
                        ClearRectangle();
                        areaTexture.Apply();
                    }
                    else
                    {
                        BackupArea();
                        isFirstGridSet = true;
                        fisrtGrid = grid;
                        WritePixel(fisrtGrid);
                        areaTexture.Apply();
                    }
                }
            }
            else
            {
                isFirstGridSet = false;
                isSecondGridSet = false;
            }
        }

        /// <summary>
        /// 复原之前刷的矩形
        /// </summary>
        private void RecoverRectangle()
        {
            int minX = Math.Min(fisrtGrid.x, secondGrid.x);
            int maxX = Math.Max(fisrtGrid.x, secondGrid.x);
            int minY = Math.Min(fisrtGrid.y, secondGrid.y);
            int maxY = Math.Max(fisrtGrid.y, secondGrid.y);
            var grid = Vector2Int.zero;

            int realCurrentAreaId = currentAreaId;
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    grid.x = x;
                    grid.y = y;
                    currentAreaId = backupAreaIdArray[x, y];
                    if (currentAreaId == 0)
                        ClearPixel(grid);
                    else
                        WritePixel(grid);
                }
            }

            currentAreaId = realCurrentAreaId;
        }

        /// <summary>
        /// 刷矩形
        /// </summary>
        private void FillRectangle()
        {
            int minX = Math.Min(fisrtGrid.x, secondGrid.x);
            int maxX = Math.Max(fisrtGrid.x, secondGrid.x);
            int minY = Math.Min(fisrtGrid.y, secondGrid.y);
            int maxY = Math.Max(fisrtGrid.y, secondGrid.y);
            var grid = Vector2Int.zero;
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    grid.x = x;
                    grid.y = y;
                    WritePixel(grid);
                }
            }
        }

        /// <summary>
        /// 清除矩形
        /// </summary>
        private void ClearRectangle()
        {
            int minX = Math.Min(fisrtGrid.x, secondGrid.x);
            int maxX = Math.Max(fisrtGrid.x, secondGrid.x);
            int minY = Math.Min(fisrtGrid.y, secondGrid.y);
            int maxY = Math.Max(fisrtGrid.y, secondGrid.y);
            var grid = Vector2Int.zero;
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    grid.x = x;
                    grid.y = y;
                    ClearPixel(grid);
                }
            }
        }

        /// <summary>
        /// 复原矩形时不能直接填充0，要先备份原始的格子数据
        /// </summary>
        private void BackupArea()
        {
            if (backupAreaIdArray == null)
            {
                backupAreaIdArray = new int[width, height];
            }

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    backupAreaIdArray[i, j] = areaIdArray[i, j];
                }
            }
        }

        protected void ResetRectangleMode()
        {
            isFirstGridSet = false;
            isSecondGridSet = false;
        }
        #endregion

    }
}
